/*
 * Copyright (c) 2021 The red-star Project
 *
 * Licensed under the Apache License, version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.inyourcode.core.threads.iml;

import com.inyourcode.core.threads.ConsumerTask;
import com.inyourcode.core.util.NamedThreadFactory;
import com.inyourcode.core.util.StackTraceUtil;
import com.inyourcode.core.threads.api.ScheduleExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *
 * 定时任务线程池
 * @author JackLei
 */
public class ScheduleExecutorFactory extends AbstractExecutorFactory<ScheduleExecutor> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleExecutorFactory.class);

    @Override
    public ScheduleExecutor newExecutor(Target target) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(coreWorks(target), new NamedThreadFactory("ASYNC"));
        return new ScheduleExecutor() {

            @Override
            public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit) {
                return executor.scheduleWithFixedDelay(command, initialDelay, period, unit);
            }

            @Override
            public void crossExecute(Executor callBackExecutor, Runnable asyncTask, ConsumerTask callBackTask) {
                execute(() -> {
                    try {
                        asyncTask.run();
                        callBackExecutor.execute(() -> {
                            try {
                                callBackTask.accept(null);
                            } catch (Exception ex) {
                                LOGGER.error("execute callback task failed, exceptioni:{}", StackTraceUtil.stackTrace(ex));
                            }
                        });
                    } catch (Exception ex) {
                        callBackExecutor.execute(() -> {
                            try {
                                callBackTask.accept(ex);
                            } catch (Exception ex2) {
                                LOGGER.error("execute exception callback task failed, exceptioni:{}", StackTraceUtil.stackTrace(ex2));
                            }
                        });
                    }
                });
            }

            @Override
            public void execute(Runnable r) {
                try {
                    executor.execute(r);
                } catch (Exception ex) {
                    LOGGER.error("execute task failed, exceptioni:{}", StackTraceUtil.stackTrace(ex));
                }
            }

            @Override
            public void shutdown() {
                executor.shutdown();
            }
        };
    }
}
